#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU
//#warning "F_CPU war noch nicht definiert, wird nun mit 3686400 definiert"
#define F_CPU 3686400UL     /* Quarz mit 3.6864 Mhz */
#endif
#include <util/delay.h>

#include "uart.h"
#define BAUD 9600UL
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)

#if ( BAUD_ERROR>10)
#error "Baud-Rate causes errors > 1 percent!!!"
#endif

uint8_t switches;
uint8_t changedvalue;
uint8_t changedbit;

void init(void)
{
  // output only on PortB
  DDRB  = 0xff;
  // turn all LEDs off
  PORTB = 0xFF;

  // input only on PortC
  DDRC  = 0x00;
  // get initial switches-state
  switches=PINC;

  // init UART
  uart_init();
}

int main (void)
{
  enum STATE_MAIN { eSTATE_INIT, eSTATE_LOOP};
  uint8_t state=0;
  uint8_t laststate=0;
  uint8_t temp, b1, b2;

  init();  
  sei(); // interrupts ON

  PORTB=0x00; // LEDs ON
  // now loop forever
  while(1)
  {
    if (state!=laststate)
    {
      //PORTB=(~(1 << state));
      laststate=state;
    }

    switch (state)
    {
      case 0:
        if (PINC != switches)
        {
          switches=PINC;
          // display current switches on LEDs INVERTED
          PORTB = ~switches;
        }

        // check for inc messages
        if (uart_get_possible()>1)
          // goto next state
          state=1;
        else
          // sleep
          _delay_ms(50);
        break;
      case 1:
        // get the characters
        if (uart_get_possible()>0)
          uart_getc_wait();
        if (uart_get_possible()>0)
          uart_getc_wait();
        // and send some response
        uart_putc(0);
        uart_putc(0);
        PORTB=0xFF; // LEDs off
        state=2;
        break;

      case 2:
        if (PINC != switches)
        {
          changedbit= switches ^ PINC;
          changedvalue=PINC & changedbit;
          switches=PINC;

          // find the position of the changed bit
          temp=0;
          while(changedbit>0)
          {
            temp++;
            changedbit=changedbit>>1;
          }

          // send the result via RS232
          uart_putc(254); // hardware #63 with SET-command
          temp=(temp<<3);
          if (changedvalue==0)
            temp = temp | 0x3;
          else
            temp = temp | 0x2;
          uart_putc(temp);
          _delay_ms(30);
        }

        if (uart_get_possible()>1)
          state=3;
        break;
      case 3:
        state=2;
        if (uart_get_possible()<2)
          break;

        b1=uart_getc_wait();
        b2=uart_getc_wait();
        if (b1==0)
        {
          // it was an init - so response ASAP
          uart_putc(0);
          uart_putc(0);
        } else if (b1==1 || b1==3)
        {
          // was a test/ping?
          uart_putc(1);
          uart_putc(3);
        } else
        {
          if (b1==254)
          {
            // set command for myself - LEDs
            temp=b2&0x1; // save the value
            b2=b2>>3;
            b2=b2-8;
            changedbit=1<<(b2-1);
            if (temp>0)
              changedvalue=PINB & ~changedbit;
            else
              changedvalue=PINB | changedbit;
            PORTB=changedvalue;
          }
        }
        break;
      default:
        break;
    }
  }

  // pointless, will never be reached
  return 0;
}
